#include <iostream>
#include <vector>
#include <unistd.h>


#include "Thread.hpp"


#define NR_Thread 4


int ticket = 10000;



struct ThreadData{
    std::string _name;
    // 共用同一块锁
    pthread_mutex_t *_plock;
};

void BuyTicket(ThreadData td){
    while(true)
    {
        pthread_mutex_lock(td._plock);
        if(ticket > 0){
            usleep(1000);
            ticket--;
            printf("get a ticket, who get: %s ,remain: %d\n", td._name.c_str(),ticket);    
            pthread_mutex_unlock(td._plock);
            
            // 模拟入库操作，让其他线程有时间睡醒然后切换线程。 
            // usleep(50);
            // usleep(10);
            usleep(1);
        }
        else{
            pthread_mutex_unlock(td._plock);
            break;
        }
    }
}

int main(){

    pthread_mutex_t lock;
    pthread_mutex_init(&lock, nullptr);

    std::vector<ThreadModule::Thread<ThreadData>> threads;
    for(int i = 0; i < NR_Thread; ++i)
    {
        ThreadData *td = new ThreadData;
        td->_plock = &lock;
        threads.emplace_back(BuyTicket, *td);
        td->_name = threads.back().Name();
        printf("Creating thread: %s\n", td->_name.c_str());
    }

    for(ThreadModule::Thread<ThreadData> &thread : threads){
        printf("thread start: %s\n", thread.Name().c_str());
        // pause();
        thread.Start();
    }
    for(ThreadModule::Thread<ThreadData> &thread : threads){
        // pause();
        thread.Join();
    }
    // pause();
    pthread_mutex_destroy(&lock);
    return 0;
}




// // 代码最后产生了负数
// #define NR_Thread 100


// int ticket = 10000;

// void BuyTicket(){
//     while(true)
//     {
//         if(ticket > 0){
//             usleep(10000);
//             ticket--;
//             printf("get a ticket, remain: %d\n", ticket);     
//         }
//         else{
//             break;
//         }
//     }
// }


// int main(){

//     std::vector<ThreadModule::Thread> threads;
//     for(int i = 0; i < NR_Thread; ++i)
//     {
//         threads.emplace_back(BuyTicket);
//     }

//     for(ThreadModule::Thread &thread : threads){
//         thread.Start();
//     }
//     for(ThreadModule::Thread &thread : threads){
//         thread.Join();
//     }
//     return 0;
// }